#include "myserver.h"
// #include <spdlog/spdlog.h>

MyServer::MyServer()
{
#ifdef DEBUG    //调试的时候看，正式发布的时候把宏注释掉
   this->m_log = spdlog::stdout_color_mt("BrainStorm");
//    console->info("welcome to spdlog!");
//    console->error("some error message with arg{}..",1);
#else
   this->m_log = spdlog::rotating_logger_mt("BrainStorm","BrainStorm",1024*1024*5,3);
   this->m_log->flush_on(spdlog::level::info);
#endif
   this->m_db = new DB("192.168.12.128","root","123456","BrainStorm");
   InitRankMap();
   //this->m_log->info("11111111111");
//    rotating_logger->flush_on(spdlog::level::info);
//    for(int i = 0 ; i < 10 ; ++i)
//    {
//        rotating_logger->info("{} * {} equals {:>10}",i,i,i*i);
//    }
}

void MyServer::connectEvent(TcpSocket *s)
{

   this->m_log->info("有一个新连接[{}:{}]",s->getIp(),s->getPort());
}

void MyServer::readEvent(TcpSocket *s)
{
//    char buf[1024];
//    s->readData(buf,1024);
//    printf("client send msg: %s \n",buf);
//    printf("current thread id : %ld\n",pthread_self());
   char buf[1024] = {0} ;
   while(1)
   {
       int len = 0 ;
       s->readData(&len,sizeof(len));
       if(len <=0 )
           break;
       s->readData(buf,len);

       //数据解析
       Json::Value root ;
       Json::Reader reader; // Json解析器
       if(!reader.parse(buf,root)) //Buf是一个输入字节流，里面是json格式的字符串，把他转化成root格式，如果没有转化成功，说明数据不对
       {
           this->m_log->error("json 数据解析失败!");
           return ;
       }
       // 成功了就可以从root 里把数据提取出来

       int cmd = root["cmd"].asInt();
       switch(cmd)
       {
           case REGISTER:
               Register(s,root);
               break;
           case LOGIN:
               Login(s,root);
               break;
           case SINGLE_GETQUESTION:
               SingleGetQuestion(s);
               break;
           case RANK:
               Rank(s);
               break;
           case ANSWER:
               RankAnswerOneQuestion(s,root);
                   break;
           case RANKRESULT:
               std::cout<<"打完了，给出结果"<<std::endl;
               RankResult(s,root);
               break;
           default:
               break;
       }
   }
}

void MyServer::writeEvent(TcpSocket *)
{

}

void MyServer::closeEvent(TcpSocket *s, short)
{
  // printf("client quit ,ip: %s , port : %d\n",s->getIp(),s->getPort());

   //将用户从 等待 rank 的队列中删除,设置一个局部锁，用大括号，大括号结束锁直接释放掉
   {
       std::unique_lock<std::mutex> lock(this->RankLock);
       int rank  = this->users[s->getUserName()]->GetRank();
       auto it = this->RankQueue.find(rank);
       if(it != this->RankQueue.end())
       {
           this->RankQueue.erase(it);
       }
   }


   std::unique_lock<std::mutex> lock(this->userLock);
   //迭代器it，把列表从头找到尾，找到现在要关闭的这个歌客户端的socket指针，从列表中删除，
   std::map<std::string,User*>::iterator it = this->users.begin();
   while(it != this->users.end())
   {
       if(it->second->getSocket() == s)
       {
           this->users.erase(it);
           this->m_log->info("用户 {} {} : {} quit",it->second->getName(),s->getIp(),s->getPort());

           //释放user
           delete it->second;
           return;
       }
       it++;
   }
   this->m_log->info(" {} : {} quit",s->getIp(),s->getPort());
}

void MyServer::writeData(TcpSocket *s, const Json::Value &inJson)
{
   std::string data = inJson.toStyledString(); //标准的Json格式的字符串
   s->writeData(data.c_str(),data.length());

}

void MyServer::Register(TcpSocket *s, const Json::Value &inJson)
{
   std::string userName = inJson["userName"].asCString();
   std::string passwd = inJson["passwd"].asCString();

   //检测用户是否已经存在

   char sql[100] = {0};
   sprintf(sql,"select *from user where name = '%s' and passwd = '%s';",userName.c_str(),passwd.c_str());

   int result = OK ;

   Json::Value outJson;//查出来的语句放到这个里面
   bool ret = m_db->db_select(sql,outJson);

   if(!ret)
   {
       result = ERROR ;
       m_log->error("Register select user error");
   }

   if(outJson.isMember("Name")) // IsMember  是否存在这个字段      //用户存在，表明已经注册过了
       result = USEREXIST ;
   else
   {
       sprintf(sql,"insert into user(Name,Passwd,`Rank`) values('%s','%s',0);",userName.c_str(),passwd.c_str());
       std::cout << sql << std::endl;
       bool ret = m_db->db_exec(sql);
       if(!ret)
       {
           result = ERROR ;
           m_log->error("Register insert user error");
       }
       else
       {
           m_log->info("Register user = {} succeed",userName);
       }
   }

   Json::Value json;
   json["cmd"] = REGISTER;
   json["result"] = result ;

   writeData(s,json);


}

void MyServer::Login(TcpSocket *s, const Json::Value &inJson)
{
   std::string userName = inJson["userName"].asCString();
   std::string passwd = inJson["passwd"].asCString();

   //检测用户是否已经注册过
   int rank = 0;
   char sql[100] = {0};
   sprintf(sql,"select *from user where name = '%s' and passwd = '%s';",userName.c_str(),passwd.c_str());

   int result = OK ;

   Json::Value outJson;//查出来的语句放到这个里面
   bool ret = m_db->db_select(sql,outJson);

   if(ret)
   {
       result = ERROR ;
       m_log->error("Login select user error");
   }

   if(outJson.isMember("Name")) // IsMember  是否存在这个字段      //用户存在，表明已经注册过了
   {
       std::unique_lock<std::mutex> lock(this->userLock);
       if(this->users.find(userName) != this->users.end()) // 用户已经登陆
           result = USEREXIST;
       else
       {
           int i = 0 ;
           rank = atoi(outJson["Rank"][i].asString().c_str());

           result = OK ;
           User *user = new  User(userName,passwd,rank,s);
           this->users.insert(make_pair(userName,user));
           this->m_log->info("用户 {} {} : {} 登录成功",userName,s->getIp(),s->getPort());
           s->setUserName(userName);
        }
   }
   else
   {
       result = NAMEORPASSWD;
   }



   Json::Value json;
   json["cmd"] = LOGIN;
   json["result"] = result ;
   json["userName"] = userName;
   json["rank"] = this->rankMap[rank];
    std::cout << "enemy: Name:" << json["userName"] << " Rank:" << json["rank"]  << std::endl;
   writeData(s,json);
}

void MyServer::SingleGetQuestion(TcpSocket *s)
{
   char sql[100];
   sprintf(sql,"select *from question order by rand() limit %d;",QUESTION_NUM);

   int result = OK ;
   Json::Value outJson;//查出来的语句放到这个里面
   bool ret = m_db->db_select(sql,outJson);

   if(!ret || outJson["question"].size() != QUESTION_NUM )
   {
       result = ERROR ;
       m_log->error("Single  Get   Question error");
   }
   Json::Value json ;
   json["cmd"] = SINGLE_GETQUESTION;
   json["result"] = result ;
   json["question"] = outJson ;

   this->m_log->info("user{}[{}:{}] get question : {}\n",s->getUserName(),s->getIp(),s->getPort(),json.toStyledString());

   writeData(s,json);
}





void MyServer::InitRankMap()
{
   char buf[100];
   int rank = 0 ;
   int num = 0 ;
   for(int i = 0 ; i < 100 ; i ++)
   {
       if(i < 9)
       {
           rank = i /3 ;
           num = i % 3 ;
           sprintf(buf,"青铜%d %d 颗星",3-rank,num+1);
       }
       else if(9 <= i && i < 10)
       {
           rank = (i-9) / 3 ;
           num = (i-9) % 3 ;
           sprintf(buf,"白银%d %d 颗星",3-rank,num+1);
       }
       else if(18 <= i && i < 34)
       {
           rank = (i-18) / 4 ;
           num = (i-18) % 4 ;
           sprintf(buf,"黄金%d %d 颗星",4-rank,num+1);
       }
       else if(34 <= i && i < 50)
       {
           rank = (i-34) / 5 ;
           num = (i-34) % 5 ;
           sprintf(buf,"铂金%d %d 颗星",4-rank,num+1);
       }
       else if(50 <= i && i < 75)
       {
           rank = (i-50) / 5 ;
           num = (i-50) % 5 ;
           sprintf(buf,"钻石%d %d 颗星",5-rank,num+1);
       }
       else if(75 <= i && i < 100)
       {
           rank = (i-75) / 5 ;
           num = (i-75) % 5 ;
           sprintf(buf,"星耀%d %d 颗星",5-rank,num+1);
       }

       this->rankMap.insert(std::make_pair(i,buf));
   }
//    for(int i = 0 ; i < 100 ; i++)
//    {
//        std::cout << i << " : " << this->rankMap[i] << std::endl ;
//    }
}

void MyServer::Rank(TcpSocket *s)
{

   TcpSocket *other = NULL ;   //对手

   //User* user = this->users[s->getUserName()];
   int rank = this->users[s->getUserName()]->GetRank() ;       //当前用户的 rank积分


   std::unique_lock<std::mutex> lock(this->RankLock);
   //查找同一段位的对手
   std::map<int,TcpSocket*>::iterator it = this->RankQueue.find(rank);

   if(it != this->RankQueue.end())
   {
       other = it->second;
       this->RankQueue.erase(it);
   }
   else
   {
       //查找其他段位的选手 积分差值的绝对值小于5 都可以对决
       for(int i = 1 ; i <= 5 ; i++)
       {
           it = this->RankQueue.find(rank+i);
           if(it != this->RankQueue.end())
           {
               other = it->second;
               this->RankQueue.erase(it);
               break;
           }
           it = this->RankQueue.find(rank-i);
           if(it != this->RankQueue.end())
           {
               other = it->second;
               this->RankQueue.erase(it);
               break;
           }
       }
   }
   this->m_log->info("rank 分数: {}",rank);
   if(other == NULL)       //没有匹配到用户
   {
       this->RankQueue.insert(std::make_pair(rank,s));
       this->m_log->info("当前等待的 rank 人数: {}",this->RankQueue.size());

   }
   else    //找到
   {
       //开始对决

       StartRank(s,other);



   }


}

void MyServer::StartRank(TcpSocket *first, TcpSocket *second)
{
   char sql[100];
   sprintf(sql,"select *from question order by rand() limit %d;",QUESTION_NUM);

   int result = OK ;
   Json::Value outJson;//查出来的语句放到这个里面
   bool ret = m_db->db_select(sql,outJson);

   if(!ret || outJson["question"].size() != QUESTION_NUM )
   {
       result = ERROR ;
       m_log->error("start rank select question error");
   }
   Json::Value json ;
   json["cmd"] = RANK;
   json["result"] = result ;
   json["question"] = outJson ;

   //first user
   json["enemyName"] = second ->getUserName();
   json["enemyRank"] = this->rankMap[this->users[second->getUserName()]->GetRank()];
   json["enemyScore"] = 0;

   writeData(first,json);

   //second user
   json["enemyName"] = first ->getUserName();
   json["enemyRank"] = this->rankMap[this->users[first->getUserName()]->GetRank()];

   writeData(second,json);

   this->m_log->info("获取 rank 题目: {}\n",json.toStyledString());
}

void MyServer::RankAnswerOneQuestion(TcpSocket *s, const Json::Value &inJson)
{
   std::string enemyName = inJson["enemyName"].asString();
   User* user = this->users[enemyName];

   Json::Value json ;
   json["cmd"] = ANSWER;
   json["enemyScore"] = inJson["score"].asInt() ;
   json["enemyQuestionId"] = inJson["questionId"].asInt();
   writeData(user->getSocket(),json);
}

void MyServer::RankResult(TcpSocket *s, const Json::Value &inJson)
{
   std::unique_lock<std::mutex> lock(this->userLock);
   User * user = this->users[s->getUserName()];

   int score = inJson["score"].asInt();
   int enemyScore = inJson["enemyScore"].asInt();

   if(score < enemyScore)
   {
       user->SetRank(user->GetRank()-1);
   }
   else if(score > enemyScore)
   {
       user->SetRank(user->GetRank()+1);
   }

   Json::Value json ;
   json["cmd"] = RANKRESULT;
   json["newRank"] = this->rankMap[user->GetRank()] ;
   writeData(s,json);

}


























